#include "dllmain.h"

FILE* g_Log = NULL;
char logDir[260];

DWORD dwReset;
DWORD dwPresent;

typedef HRESULT (__stdcall* Reset_t)(LPDIRECT3DDEVICE9,D3DPRESENT_PARAMETERS*);
typedef HRESULT (__stdcall* Present_t)(LPDIRECT3DDEVICE9,CONST RECT* ,CONST RECT*,HWND ,CONST RGNDATA*);

Reset_t pReset;
Present_t pPresent;

void Log(const char* msg,...)
{
	if(logDir == NULL)
		return;

	SYSTEMTIME time;
	va_list ap;
	if(g_Log == NULL)
	{
		char	filename[512];
		_snprintf( filename, sizeof(filename), "%s\\%s", logDir, "SAMPHookLib.log" );

		g_Log = fopen( filename, "w" );
		if ( g_Log == NULL )
			return;
	}
	GetLocalTime(&time);
	fprintf( g_Log, "[%02d:%02d:%02d.%03d] ", time.wHour, time.wMinute, time.wSecond, time.wMilliseconds );
	va_start( ap, msg );
	vfprintf( g_Log, msg, ap );
	va_end( ap );
	fprintf( g_Log, "\n" );
	fflush( g_Log );
};


SAMPBase samp;
bool bDataCompare(const BYTE* pData, const BYTE* bMask, const char* szMask)
{
	for(;*szMask;++szMask,++pData,++bMask)
		if(*szMask=='x' && *pData!=*bMask )
			return false;
	return (*szMask) == NULL;
}

DWORD dwFindPattern(DWORD dwAddress,DWORD dwLen,BYTE *bMask,char * szMask)
{
	for(DWORD i=0; i < dwLen; i++)
		if( bDataCompare( (BYTE*)( dwAddress+i ),bMask,szMask) )
			return (DWORD)(dwAddress+i);
	return 0;
}

bool init = false;

HRESULT __stdcall hkPresent(LPDIRECT3DDEVICE9 pDevice,CONST RECT* pSourceRect,CONST RECT* pDestRect,HWND hDestWindowOverride,CONST RGNDATA* pDirtyRegion)
{
	samp.Initialize();
	return pPresent(pDevice,pSourceRect,pDestRect, hDestWindowOverride,pDirtyRegion);
}

HRESULT __stdcall hkReset(LPDIRECT3DDEVICE9 pDevice,D3DPRESENT_PARAMETERS* pPresentationParameters)
{
		return pReset(pDevice,pPresentationParameters);
}
void Hook()
{
	HMODULE hModule = NULL;
	  char buffer[MAX_PATH];
    
    // Getting path to system dir and to d3d8.dll
	::GetSystemDirectory(buffer,MAX_PATH);

	// Append dll name
	strcat(buffer,"\\d3d9.dll");
	Log("load d3d9.dll");
	while( !hModule )
	{
		hModule = GetModuleHandleA( buffer );// "d3d9.dll" ); // Handle zur DLL holen
		Sleep( 100 ); // 100ms warten
	}
	Log("d3d9.dll loaded");


	DWORD* VTableStart = 0;
	DWORD DevicePointer = dwFindPattern((DWORD)hModule, 0x128000,
		(PBYTE)"\xC7\x06\x00\x00\x00\x00\x89\x86\x00\x00\x00\x00\x89\x86", "xx????xx????xx");
	memcpy(&VTableStart, (void*)(DevicePointer+2), 4);

	dwReset = (DWORD)VTableStart[16];
	dwPresent = (DWORD)VTableStart[17];


	pReset = (Reset_t)DetourFunction((PBYTE)dwReset,(PBYTE)hkReset);

	pPresent = (Present_t)DetourFunction((PBYTE)dwPresent,(PBYTE)hkPresent);

}
void Thread(LPVOID arg)
{
	//Log("wait 60 seconds");
	//Sleep(60000);
	Log("Init samp class");
	samp.Initialize();
	//samp.AddToChatWindow("Hallo wie geht es dir?",RGB(255,255,255));
}

extern "C" void __declspec(dllexport) SMessage(char* msg)
{
	samp.SendCommandToServer(msg);
};

BOOL APIENTRY DllMain(HMODULE hMod, DWORD reason,LPVOID lpReserved)
{
	switch(reason)
	{
	case DLL_PROCESS_ATTACH:
		{
			if (GetModuleFileName(hMod, logDir, sizeof(logDir) - 32) != 0 )
			{
				if ( strrchr(logDir, '\\') != NULL )
					*strrchr( logDir, '\\' ) = 0;
				else
					strcpy( logDir, "." );
			}
			//DisableThreadLibraryCalls( hMod );
			// Here we initialize all what we want
			Log("CreateThread Hook");
			CreateThread(0,0,(LPTHREAD_START_ROUTINE)Hook,0,0,0);
			//Thread(0);
			//CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)Thread,NULL,NULL,NULL);
		}
		break;
	case DLL_PROCESS_DETACH:
		{
			//Here we have to release all
		}
		break;
	};
	return TRUE;
};